package com.example.qianjun.gobang01.view;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import com.example.qianjun.gobang01.R;
import com.example.qianjun.gobang01.abs.AIPlayer;
import com.example.qianjun.gobang01.bean.Constant;
import com.example.qianjun.gobang01.bean.GobangCheckboard;
import com.example.qianjun.gobang01.bean.PreviousStep;
import com.example.qianjun.gobang01.robot_player.NovicePlayer;
import com.example.qianjun.gobang01.util.GobangUtil;
import com.example.qianjun.gobang01.util.ReferenceInit;

/**
 * Created by qianjun on 2016/5/2.
 */
public class GobangPanel extends View {
    private Paint mPaint = new Paint();

    private int mPanelwidth;
    private float mLineheight;
    private Bitmap mWhitePiece;
    private Bitmap mBlackPiece;
    //黑白棋子尺寸保存
    private Bitmap mWhitePieceScale;
    private Bitmap mBlackPieceScale;

    //棋子占棋盘格的比例
    private float ratioPieceOfLineHeight = 3 * 1.0f / 4;
    //提示方格占棋盘格的比例
    private float ratioNoticeOfLineHeight = 5 * 1.0f / 6;
    //提示方格边长
    private int noticeLenght;


    private GobangCheckboard gobangCheckboard;
    public int MAX_PIECES_WIN = Constant.FIVE_PIECES_WIN;
    private int table_x = Constant.SMALL_CHECKBOARD_X;
    private int table_y = Constant.SMALL_CHECKBOARD_Y;
    private int[][] table;
    //对话框
    private AlertDialog.Builder builder;
    //为true时，表示黑棋下
    private boolean mIsBlackOrWhite = true;
    //获胜者
    private int winner = Constant.NO_VICTORY_OR_DEFEAT;

    //机器人棋手
    private AIPlayer robotPlayer;

    //提示机器人棋手
    private AIPlayer noticeRobotplayer;

    //提示机器人棋手下棋时间标志位，防止超时,为true时表示在时间范围内，可以进行提示
    private boolean noticeRobotNextPieceInTime = true;

    //机器人水平
    private int robotLevel = Constant.ROBOT_LEVEL_FIRST;
    //提示机器人等级
    private int noticeRobotLevel = Constant.ROBOT_LEVEL_FOURTH;
    //工具类
    private GobangUtil gobangUtil;
    //对弈模式：人人还是人机，暂时写成人机
    private int chessMode = Constant.HUMAN_PK_ROBOT;

    //人选择先手还是后手,执黑还是执白，默认是执黑先行
    private int chessOrder = Constant.CHOSE_WHITE_FIRST;

    //机器人先走步标志位,为true表示先下，为false表示后下
    private boolean robotPlayFirst = false;

    //机器人棋子颜色，为true表示黑色，为false表示白色，默认白色
    private boolean robotPieceColor = false;
    //人类棋手棋子颜色，为true表示黑色，为false表示白色，默认黑色
    private boolean humanPieceColor = true;

    //落子提示框外形，目前有方形、圆形可选，默认选择方形
    private int pieceNoticeStyle = Constant.PIECE_NOTICE_STYLE_RECT;

    //随着手指移动的棋子
    private Point movingPiece = Constant.NO_POINT;

    public boolean ismIsBlackOrWhite() {
        return mIsBlackOrWhite;
    }

    public int getWinner() {
        return winner;
    }

    //切换选手
    public void changPlayer() {
        mIsBlackOrWhite = !mIsBlackOrWhite;
    }

    //悔棋队列
    private PreviousStep previousStep;

    //存储设置参数
    private SharedPreferences sharedPreferences;

    //------------------------------------------------------------------------------------------//

    public boolean isNoticeRobotNextPieceInTime() {
        return noticeRobotNextPieceInTime;
    }

    public void setNoticeRobotNextPieceInTime(boolean noticeRobotNextPieceInTime) {
        this.noticeRobotNextPieceInTime = noticeRobotNextPieceInTime;
    }

    /**
     * 说明：棋盘开始时，要初始化变量，
     * 对弈模式：           chessMode
     * 机器人水平：         robotLevel
     * 先手还是后手：        chessOrder
     * 当前正在下棋的是黑子还是白子：  mIsBlackOrWhite
     */


    public int getChessOrder() {
        return chessOrder;
    }

    public void setChessOrder() {
        //下棋顺序初始化
        setChessOrderAndRobotOrder();
        this.invalidate();
    }

    //设置下棋颜色标志位
    //设置先下棋的是否是机器人
    private void setChessOrderAndRobotOrder() {
        //设置下棋颜色
        if (chessOrder == Constant.CHOSE_BLACK_FIRST || chessOrder == Constant.CHOSE_WHITE_SECOND) {
            mIsBlackOrWhite = true;
        } else if (chessOrder == Constant.CHOSE_BLACK_SECOND || chessOrder == Constant.CHOSE_WHITE_FIRST) {
            mIsBlackOrWhite = false;
        }


        /*设置棋手的棋子颜色
        *当下棋顺序为执黑先行、执黑后手时，人类棋子为黑，机器人为白
        * 当下棋顺序为执白先行、执白后手时，人类棋子为白，机器人为黑
        */
        if (chessOrder == Constant.CHOSE_BLACK_FIRST || chessOrder == Constant.CHOSE_BLACK_SECOND) {
            humanPieceColor = true;
            robotPieceColor = false;
        } else if (chessOrder == Constant.CHOSE_WHITE_FIRST || chessOrder == Constant.CHOSE_WHITE_SECOND) {
            humanPieceColor = false;
            robotPieceColor = true;
        }

        if (chessOrder == Constant.CHOSE_BLACK_SECOND || chessOrder == Constant.CHOSE_WHITE_SECOND) {
            if (chessMode == Constant.HUMAN_PK_ROBOT) {
                robotPlayFirst = true;
            }
        }

    }


    //--------------------------------------------------------------------------------------------------

    //初始化参数设置
    public void paramsConfiginit() {
        sharedPreferences = getContext().getSharedPreferences("gobangConfig", Context.MODE_PRIVATE);
        table_x = sharedPreferences.getInt("table_x", Constant.SMALL_CHECKBOARD_X);
        table_y = sharedPreferences.getInt("table_y", Constant.SMALL_CHECKBOARD_Y);
        robotLevel = sharedPreferences.getInt("robotPlayerLevel", Constant.ROBOT_LEVEL_FIRST);
        noticeRobotLevel = sharedPreferences.getInt("noticeRobotplayerLevel", Constant.ROBOT_LEVEL_FIRST);
        chessOrder = sharedPreferences.getInt("chessOrder", Constant.CHOSE_BLACK_FIRST);
        pieceNoticeStyle = sharedPreferences.getInt("pieceNoticeStyle", Constant.PIECE_NOTICE_STYLE_RECT);

    }


    public int getChessMode() {
        return chessMode;
    }

    public void setChessMode(int chessMode) {
        this.chessMode = chessMode;
    }

    public int getRobotLevel() {
        return robotLevel;
    }


    //初始化
    public void init() {
        ReferenceInit.init(table_x, table_y, robotLevel);
        gobangCheckboard = ReferenceInit.gobangCheckboard;
        gobangUtil = ReferenceInit.getGobangUtil();
        robotPlayer = ReferenceInit.getRobotPlayer();
        noticeRobotplayer = ReferenceInit.getRobotPlayer(noticeRobotLevel);
        table = gobangCheckboard.getTable();

        //图片加载
        mWhitePiece = BitmapFactory.decodeResource(getResources(), R.drawable.stone_w2);
        mBlackPiece = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1);

    }

    //构造函数
    public GobangPanel(Context context, AttributeSet attrs) {
        super(context, attrs);

        //参数初始化
        paramsConfiginit();
        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int width = Math.min(widthSize, heightSize);
        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize;
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize;
        }

        setMeasuredDimension(width, width);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mPanelwidth = w;
        mLineheight = mPanelwidth * 1.0f / table_x;

        int piecewidth = (int) (mLineheight * ratioPieceOfLineHeight);
        //提示方格的长度
        noticeLenght = (int) (mLineheight * ratioNoticeOfLineHeight);


        mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece, piecewidth, piecewidth, false);
        mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, piecewidth, piecewidth, false);
        mBlackPieceScale = mBlackPiece;
        mWhitePieceScale = mWhitePiece;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBoard(canvas);
        drawPieces(canvas);
        if (robotPlayFirst) {
            robotPlayFirst = false;
            robotPlacePiece();
        }

        //绘制移动棋子
        movingPieceJudge(canvas);
    }

    //条件判断：当机器人落子时，不能绘制移动棋子
    private void movingPieceJudge(Canvas canvas) {
        if (movingPiece != Constant.NO_POINT) {
            if (chessMode == Constant.HUMAN_PK_ROBOT) {
                if (humanPieceColor == mIsBlackOrWhite) {

                    if (table[movingPiece.x][movingPiece.y] == Constant.NO_PIECES) {
                        drawMovingpiece(canvas);
                    }

                }
            } else if (chessMode == Constant.HUMAN_PK_HUMAN) {
                if (table[movingPiece.x][movingPiece.y] == Constant.NO_PIECES) {
                    drawMovingpiece(canvas);
                }
            }
        }

    }

    //绘制移动棋子
    private void drawMovingpiece(Canvas canvas) {
        if (movingPiece.x != Constant.NO_POINT.x && movingPiece.y != Constant.NO_POINT.y) {
            noticePaintinit();

            if (pieceNoticeStyle == Constant.PIECE_NOTICE_STYLE_RECT) {
                //方形提示框
                canvas.drawRect(new RectF((movingPiece.x + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight, (movingPiece.y + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight, (movingPiece.x + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight + noticeLenght, (movingPiece.y + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight + noticeLenght), mPaint);

            } else if (pieceNoticeStyle == Constant.PIECE_NOTICE_STYLE_CYCLE) {
                //圆形提示框
                canvas.drawCircle((movingPiece.x + 0.5f) * mLineheight, (movingPiece.y + 0.5f) * mLineheight, 2.3f / 5 * mLineheight, mPaint);
            }

        }
    }

    //棋盘画笔设置
    private void boardPaintinit() {
        //画笔设置
        mPaint.setAlpha(10);
        mPaint.setColor(Color.rgb(0x8b, 0x8b, 0x83));
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    //提示画笔设置
    private void noticePaintinit() {
        //画笔设置
        mPaint.setAlpha(100);
        mPaint.setColor(Color.RED);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);

        //虚线设置，数组中：先画8的实线，再画4的虚线,2的实线，1的虚线；后面的为偏移量
        PathEffect effect = new DashPathEffect(new float[]{8, 4, 2, 1}, 1);
        mPaint.setPathEffect(effect);
        mPaint.setStyle(Paint.Style.STROKE);

    }


    //绘制棋盘
    private void drawBoard(Canvas canvas) {
        //初始化棋盘画笔
        boardPaintinit();
        int w = mPanelwidth;
        float lineHeight = mLineheight;
        for (int i = 0; i < table_x; i++) {
            int startX = (int) (lineHeight / 2);
            int endX = (int) (w - lineHeight / 2);

            int y = (int) ((0.5 + i) * lineHeight);
            canvas.drawLine(startX, y, endX, y, mPaint);
            canvas.drawLine(y, startX, y, endX, mPaint);

        }
    }

    //绘制棋子
    private void drawPieces(Canvas canvas) {
        for (int i = 0; i < table_x; i++) {
            for (int j = 0; j < table_y; j++) {
                if (table[i][j] == Constant.WHITE_PIECE) {
                    canvas.drawBitmap(mWhitePieceScale, (i + (1 - ratioPieceOfLineHeight) / 2) * mLineheight, (j + (1 - ratioPieceOfLineHeight) / 2) * mLineheight, null);


                } else if (table[i][j] == Constant.BLACK_PIECE) {
                    canvas.drawBitmap(mBlackPieceScale, (i + (1 - ratioPieceOfLineHeight) / 2) * mLineheight, (j + (1 - ratioPieceOfLineHeight) / 2) * mLineheight, null);


                }
            }
        }

        //绘制最后落子的棋子的外边框
        lastPieceNotice(canvas);

    }

    //绘制最后一个落子外边框
    private void lastPieceNotice(Canvas canvas) {
        noticePaintinit();
        Point lastPoint = ReferenceInit.getGobangCheckboard().getPreviousStep().seeFirstpoint();
        if (lastPoint.x != Constant.NO_POINT.x && lastPoint.y != Constant.NO_POINT.y) {

            if (pieceNoticeStyle == Constant.PIECE_NOTICE_STYLE_RECT) {
                //方形提示框
                canvas.drawRect(new RectF((lastPoint.x + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight, (lastPoint.y + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight, (lastPoint.x + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight + noticeLenght, (lastPoint.y + (1 - ratioNoticeOfLineHeight) / 2) * mLineheight + noticeLenght), mPaint);

            } else if (pieceNoticeStyle == Constant.PIECE_NOTICE_STYLE_CYCLE) {
                //圆形提示框
                canvas.drawCircle((lastPoint.x + 0.5f) * mLineheight, (lastPoint.y + 0.5f) * mLineheight, 2.3f / 5 * mLineheight, mPaint);
            }


        }

    }

    //重写触屏点击事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (gobangCheckboard.isStop()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                int x = (int) (event.getX() / mLineheight);
                int y = (int) (event.getY() / mLineheight);
                movingPiece = new Point(x, y);
                this.invalidate();
                break;
            case MotionEvent.ACTION_UP:
                x = (int) (event.getX() / mLineheight);
                y = (int) (event.getY() / mLineheight);
                Point point = new Point(x, y);
                //该点是否有棋子标志位
                boolean pieceExistenceOrNot = table[point.x][point.y] == Constant.NO_PIECES;
                //人机对弈模式
                if (chessMode == Constant.HUMAN_PK_ROBOT) {

                    //判断该点是否已经存在棋子，若存在，则不落子
                    if (pieceExistenceOrNot) {

                        //如果当前棋子颜色与人类棋手棋子颜色一致，则允许落子
                        if (mIsBlackOrWhite == humanPieceColor) {
                            humanPlacePiece(point);
                            checkWinner(point);
                        }

                    }


                    //人人对弈模式
                } else if (chessMode == Constant.HUMAN_PK_HUMAN) {
                    if (pieceExistenceOrNot) {
                        humanPlacePiece(point);
                        checkWinner(point);
                    }

                }

                break;
        }

        return true;
    }

    //人落子,传入当前坐标
    private void humanPlacePiece(Point point) {
        //落子的时候，移动棋子重置
        movingPiece = Constant.NO_POINT;

        //判断是白子还是黑子，并写入棋盘
        if (mIsBlackOrWhite) {
            gobangCheckboard.putChessPiece(point, Constant.BLACK_PIECE);
        } else {
            gobangCheckboard.putChessPiece(point, Constant.WHITE_PIECE);
        }
        mIsBlackOrWhite = !mIsBlackOrWhite;
        //通知重新绘制棋盘
        this.invalidate();

    }

    //机器落子
    private Point robotPlacePiece() {
        int pieceType;
        if (mIsBlackOrWhite) {
            pieceType = Constant.BLACK_PIECE;
        } else {
            pieceType = Constant.WHITE_PIECE;
        }
        Point robotPoint = robotPlayer.findBestPoint(pieceType);

        gobangCheckboard.putChessPiece(robotPoint, pieceType);

        mIsBlackOrWhite = !mIsBlackOrWhite;
        this.invalidate();
        return robotPoint;
    }

    //提示机器人落子
    private Point noticeRobotPlacePiece() {
        int pieceType;
        if (mIsBlackOrWhite) {
            pieceType = Constant.BLACK_PIECE;
        } else {
            pieceType = Constant.WHITE_PIECE;
        }
        Point robotPoint = noticeRobotplayer.findBestPoint(pieceType);
        //如果超时，则不落子
        if (noticeRobotNextPieceInTime) {
            noticeRobotNextPieceInTime = false;
            gobangCheckboard.putChessPiece(robotPoint, pieceType);
            mIsBlackOrWhite = !mIsBlackOrWhite;
        }

        this.invalidate();
        return robotPoint;
    }

    //当时间一段时间，并且是机器人落子的时候,通知机器人落子
    public void noticeRobotPlay() {
        if (chessMode == Constant.HUMAN_PK_ROBOT) {
            //如果已经获胜，则禁止机器人下棋
            if (!gobangCheckboard.isStop()) {
                //如果机器人持有的棋子颜色与当前棋手的棋子颜色相同，则通知机器人下棋
                if (robotPieceColor == mIsBlackOrWhite) {
                    Point point = robotPlacePiece();
                    checkWinner(point);
                }

            }
        }
    }

    //判断输赢
    private void checkWinner(Point point) {
        //判断输赢
        winner = gobangUtil.isWin(point);
        if (winner != Constant.NO_VICTORY_OR_DEFEAT) {
            showResult(winner);
        }
    }

    //显示胜负信息
    private void showResult(int winner) {
        //对局结束标志
        gobangCheckboard.setStop(true);

        switch (winner) {
            case Constant.BLACK_WINNER:
                changPlayer();
                Toast.makeText(getContext(), "黑棋获胜！", Toast.LENGTH_SHORT).show();
                break;
            case Constant.WHITE_WINNER:
                changPlayer();
                Toast.makeText(getContext(), "白棋获胜！", Toast.LENGTH_SHORT).show();
                break;
            case Constant.NO_WINNER:
                Toast.makeText(getContext(), "平局！", Toast.LENGTH_SHORT).show();
                break;

        }
    }

    /**
     * 如果是人人对战，则悔棋1步
     * 如果是人机对战，则判断机器人是否落子，已经落子则悔棋2步，未落子则悔棋一步
     */
    public void backToPreviousOneOrTwoStep() {
        if (chessMode == Constant.HUMAN_PK_HUMAN) {
            backToPreviousStep();
        } else if (chessMode == Constant.HUMAN_PK_ROBOT) {

            //如果机器人已经落子，悔棋2步
            if (robotPieceColor != mIsBlackOrWhite) {
                backToPreviousStep();
                backToPreviousStep();
            } else {
                backToPreviousStep();
            }
        }
    }

    /**
     * 实现悔棋一步的功能
     */
    private void backToPreviousStep() {
        previousStep = gobangCheckboard.getPreviousStep();
        //如果胜负未分，则允许悔棋
        if (!gobangCheckboard.isStop()) {
            Point point = previousStep.getFirstPiece();
            //如果该点不是常量棋子，是棋盘上的棋子的话，允许悔棋
            if (point.x != Constant.NO_POINT.x && point.y != Constant.NO_POINT.y) {
                table[point.x][point.y] = Constant.NO_PIECES;
                //切换玩家
                changPlayer();

                //通知棋盘重新绘制
                this.invalidate();
            }
        }
    }


    /**
     * 实现提示一步的功能
     */
    public void noticeNextPiece() {

        //人人对战时，都可用提示功能，人机对战时，人类玩家可用
        if (chessMode == Constant.HUMAN_PK_HUMAN) {
            Point point = noticeRobotPlacePiece();
            checkWinner(point);
        } else if (chessMode == Constant.HUMAN_PK_ROBOT) {

            if (mIsBlackOrWhite == humanPieceColor) {
                Point point = noticeRobotPlacePiece();
                checkWinner(point);
            }
        }


    }

    /**
     * 实现认输功能
     */
    public void giveUp() {
        //如果对局没有结束，允许认输
        if (!gobangCheckboard.isStop()) {
            builder = new AlertDialog.Builder(getContext());
            builder.setTitle("提示");
            builder.setMessage("您确定要认输吗？");
            builder.setPositiveButton("认输", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (mIsBlackOrWhite) {
                        winner = Constant.WHITE_WINNER;

                    } else {
                        winner = Constant.BLACK_WINNER;

                    }

                    showResult(winner);
                    //改变当前玩家，显示胜利玩家

                }
            });
            builder.setNeutralButton("继续玩", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            });

            builder.create().show();
        }

    }
}